// 创建一个正则表达式
/***
 * 正则表达式
 *
 * 第一种写法 let reg = /pattern/
 * 第二种写法 ley reg = new RegExp('pattern')
 */

/***
 * 第一个例子 c{n}
 *
 * {1}代表一个的意思
 * /c{1}/ 匹配一个c
 * /c{2}/ 匹配两个连续的c
 * 以此类推
 * /c{n}/ 匹配n个连续的c
 */
function execReg(reg, str, level) {
  const result = reg.exec(str)
  console.log('result', result, level)
}
function test1() {
  const reg = /c{1}/
  const str = 'cainiao'
  execReg(reg, str, 25) // c
  const reg2 = /c{2}/
  const str2 = 'cainiao'
  execReg(reg2, str2, 28) // null
  const str3 = 'ccainiao'
  execReg(reg2, str3, 30) // cc
}
test1()
/**
 * 第二个例子 c{m,n}
 * /c{3,4}/ 匹配3到4个连续的c
 * 若返回结果为null，则匹配失败
 */
function test2() {
  const reg = /c{3,4}/
  const str = 'cccc'
  execReg(reg, str, 41) // cccc
  const reg2 = /c{3,4}/
  const str2 = 'cc'
  execReg(reg2, str2, 44) // null
}
test2()
/**
 * c{n,}
 * /c{3,}/ 匹配3个以上连续的c
 */
function test3() {
  const reg = /c{3,}/
  const str = 'ccc'
  execReg(reg, str, 54) //ccc
  const reg2 = /c{3,}/
  const str2 = 'cc' // null
  execReg(reg2, str2, 57)
}
test3()
/**
 * *,+,?
 * *表示0次或者多次，等同于{0,}，即c* 和 c{0,} 是一个意思。
 * +表示一次或者多次，等同于{1,}，即 c+ 和 c{1,}
 * 最后，?表示0次或者1次，等同于{0,1}，即c? 和 c{0,1} 是一个意思。
 */

/**
 * /^开头,结尾$/
 *
 * ^表示只匹配字符串的开头
 * $表示只匹配字符串的结尾
 *  若返回结果为null，则匹配失败
 */
function test4() {
  // 前面包含
  const reg = /^c/
  const str = 'cainiao'
  execReg(reg, str, 78) // c
  const str2 = 'ainiaoc'
  execReg(reg, str2, 80) // null
  // 后面包含
  const reg3 = /c$/
  const str3 = 'cainiaoc'
  execReg(reg3, str3, 84) // c
  const str4 = 'cainiao'
  execReg(reg3, str4, 86) // null
}
test4()

/**
 * /./ 匹配一个除了换行符（\n）以外的任意字符
 */
function test5() {
  const reg = /./
  const str = 'cainiao'
  execReg(reg, str, 96) // c
  // 匹配一个或多个除了\n以外的任意字符
  const reg2 = /.+/
  const str2 = 'cainiao----\nc'
  execReg(reg2, str2, 100) // cainiao----
  const reg3 = /^./
  const str3 = '\ncainiao'
  execReg(reg3, str3, 103) // null
  const str4 = 'cainiao'
  execReg(reg3, str4, 105) // c
}
test5()
// 二选一，正则表达式中的或，“|“
function test6() {
  // a|c表示，匹配a或者c。
  const reg = /a|c/
  const str = 'cainiao'
  execReg(reg, str, 113) // c
  const str2 = 'a'
  execReg(reg, str2, 115) // a
  // 这个代表以b开头匹配一个字符，或者包含c，后面跟任意字符
  const reg3 = /^b|c.+/
  const str3 = 'cainiao'
  execReg(reg3, str3, 119) // cainiao
  const str4 = 'blue'
  execReg(reg3, str4, 121) // b
  const str5 = 'acluye'
  execReg(reg3, str5, 123) // cluye
  // 优先匹配b
  const str6 = 'bbs.blueidea.com'
  execReg(reg3, str6, 125) // b
  // 如果字符串的开头是b或者c，那么匹配开头的b或者c以及其后的所有的非换行字符。
  const reg4 = /^(b|c).+/
  execReg(reg4, str6, 128) // bbs.blueidea.com
  execReg(reg4, str5, 130) // null
}
test6()
// 字符集合[a,b,c] [abc]表示a或者b或者c中的任意一个字符
function test7() {
  const reg = /[a,b,c]/
  const str = 'cainiao'
  execReg(reg, str, 137) // c
  const str2 = 'test'
  execReg(reg, str2, 139) // null
  const reg3 = /[a-z]/
  execReg(reg3, str, 141) // c
  const reg4 = /[A-Z]/
  execReg(reg4, str, 143) // null
  // 表示于小写或大写或数字中任意一个字符
  const reg5 = /[a-zA-Z0-9]/
  const str5 = 'cainiao456'
  execReg(reg5, str5, 147) // c
  // 正则的意思是开头必须是英文字母，后面是英文字母不包含数字，所以到数字结束
  const reg6 = /[a-zA-Z][a-zA-Z]+/
  const str6 = 'cainiao456test'
  execReg(reg6, str6, 151) // cainiao
  // 正则的意思是开头必须是英文字母，后面可以是英文字母或者数字以及下划线。
  const reg7 = /^[a-zA-Z][a-zA-Z0-9_]+/
  const str7 = 'cainiao456test_ddsdfdf'
  execReg(reg7, str7, 154) // cainiao456test_ddsdfdf
}
test7()
// 反字符集合[^abc] 例如[^abc]就表示不能是a，b或者c中的任何一个
function test8() {
  const reg = /[^abc]/
  const str = 'diannao'
  execReg(reg, str, 162) // d
  const str2 = 'cainiao'
  execReg(reg, str2, 164) // i
  // 由此我们可知：[^0-9]表示非数字，[^a-z]表示非小写字母，以次类推。
}
test8()
// 边界与非边界
/**
  * ^ 表示字符串的开始。
  * $ 表示字符串的结束。
  * \b 表示单词的边界，单词的边界是指不是字母、数字、下划线和汉字的任意字符。
  * \B 表示非单词的边界。
 */

function test9() {
  // /\bc/ 指的是靠边的c
  const reg = /\bc/
  const str = 'cainiaoc'
  execReg(reg, str, 178) // c
  // 因为c不是靠边的匹配不上所以返回null
  const str2 = 'aca'
  execReg(reg, str2, 183) // null
  // /\Ba/ 表示为匹配不靠边的a
  const reg2 = /\Ba/
  execReg(reg2, str, 186) // a
  execReg(reg2, str2, 187) // 后一个的c index == 2 的
}
test9()
/**
 * 数字与非数字
 * \d表示数字的意思
 * \D表示非数字
 * 匹配一个数字字符
 */
function test10() {
  const reg = /\d/
  const str = 'cainiao123'
  execReg(reg, str, 198) // 1
  const str2 = 'cainiaoc'
  execReg(reg, str2, 201) // null
  // \D表示非数字
  const reg2 = /\D/
  const str3 = 'cainiaoc'
  execReg(reg2, str3, 205) // c
  const str4 = '123cainiao'
  execReg(reg2, str4, 207) //c
}
test10()
/**
 * 空白
 * \f匹配换页符
 * \n匹配换行符
 * \r匹配回车
 * \t匹配制表符
 * \v匹配垂直制表符
 * s匹配单个空格，等同于[\f\n\r\t\v]
 * 同样，\S表示非空格字符。
 */
function test11() {
  // \s匹配单个空格.匹配一个除了\n的任意字符+匹配一个或多个
  const reg = /\s.+/
  const str = ' cainiao__________\n__________'
  execReg(reg, str, 222) // ' cainiao__________'
  // \S表示非空格字符。+匹配一个或多个
  const reg2 = /\S+/
  execReg(reg2, str, 227) // 'cainiao__________'
  const str2 = 'This is a test String.'
  execReg(reg2, str2, 229) // 'This'
}
test11()
/**
 * 单词字符
 * \w表示单词字符，等同于字符集合[a-zA-Z0-9_]  匹配一个小写或大写或数字或下划线字符
 * \W表示非单词字符，等效于[^a-zA-Z0-9_] 
 */
function test12() {
  const reg = /\w/
  const str = 'cainiao'
  execReg(reg, str, 239) // c
  const str1 = '_1'
  execReg(reg, str1, 241) // _
  const str2 = '123'
  execReg(reg, str2, 243) // 1
  // 皮论一个或多个单词字符
  const reg1 = /\w+/
  execReg(reg1, str, 246) // cainiao
  execReg(reg1, str1, 247) // _1
  execReg(reg1, str2, 248) // 123
  const str3 = '\n_123'
  execReg(reg1, str3, 250) // _123
  const str4 = '中'
  execReg(reg1,str4,252) // null
  // \W表示非单词字符，等效于[^a-zA-Z0-9_]
  const reg2 = /\W/
  execReg(reg2, str3, 256) // \n
  execReg(reg2, str4, 257) // 中
}
test12()
/**
 * 正则表达式的修饰符
 * 全局匹配，修饰符g 形式：/pattern/g
 * 不区分大小写，修饰符i 形式：/pattern/i
 * 行首行尾，修饰符m 形式：/pattern/m
 */
function test13() {
  // 全局匹配g 匹配一个
  const reg = /c/g
  const str = 'aiciaoc'
  execReg(reg, str, 270) // c
  const reg2 = /c/i
  const str2 = 'niaoC'
  execReg(reg2, str2, 273) // C index = 4
  const reg3 = /c/m
  const str3 = 'aic\nc'
  execReg(reg3, str3, 276) // c index = 2
}
test13()
/**
 * test方法
 * test方法仅仅检查是否能够匹配str，并且返回布尔值以表示是否成功。
 * 形式：reg.test(str)
 */
function testReg(reg, str,level) {
  return console.log(reg.test(str),level)
}
// 正则表示为是否以b开头
const reg = /^b/
const str = 'abbbb'
testReg(reg, str, 288)  // false,288
const str2 = 'basss'
testReg(reg, str2, 290) // true,290
/**
 * 使用字符串的方法执行正则表达式
 * match方法
 * 表示 str.test(reg)
 * 可见，和exec的结果一样。
 */
function matchReg(reg, str,level) {
  return console.log(str.match(reg),level)
}
matchReg(reg, str, 301) // null,301
matchReg(reg, str2, 302) // b,302
/**
 * replace方法
 * 形式：str. replace (reg,’new str’);
 */
function replaceReg() {
  // 匹配开头为数字大小写下划线空格 /g 全局匹配
  const reg = /[^a-zA-Z0-9_\s]/g
  const str = 'Test is name 1 mengxinhai'
  const str2 = str.replace(reg, '')
  console.log('str2', str2) // Test is name 1 mengxinhai
  const str3 = str.replace(/\w+/g, 'word')
  console.log('str3', str3) // word word word word word
  const str4 = str.replace(/\w+/, 'word')
  console.log('str4', str4) // word is name 1 mengxinhai
}
replaceReg()